﻿namespace LogManager.Gui.Helpers
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Linq;

    public static class ObservableCollectionHelpers
    {
        public static ReadOnlyObservableCollection<Tresult> GetSyncWrapper<Tresult, Tsource>(this ObservableCollection<Tsource> sources, Func<Tsource, Tresult> createResult)
            where Tsource : class
        {
            var results = new ObservableCollection<Tresult>();
            sources.CollectionChanged += (object sender, NotifyCollectionChangedEventArgs e) =>
            {
                switch (e.Action)
                {
                    case NotifyCollectionChangedAction.Add:
                        for (int i = 0; i < e.NewItems.Count; i++)
                        {
                            results.Insert(e.NewStartingIndex + i, createResult((Tsource)e.NewItems[i]));
                        }
                        break;

                    case NotifyCollectionChangedAction.Move:
                        if (e.OldItems.Count == 1)
                        {
                            results.Move(e.OldStartingIndex, e.NewStartingIndex);
                        }
                        else
                        {
                            List<Tresult> items = results.Skip(e.OldStartingIndex).Take(e.OldItems.Count).ToList();
                            for (int i = 0; i < e.OldItems.Count; i++)
                                results.RemoveAt(e.OldStartingIndex);

                            for (int i = 0; i < items.Count; i++)
                                results.Insert(e.NewStartingIndex + i, items[i]);
                        }
                        break;

                    case NotifyCollectionChangedAction.Remove:
                        if (e.OldItems != null)
                            for (int i = 0; i < e.OldItems.Count; i++)
                                results.RemoveAt(e.OldStartingIndex);
                        break;

                    case NotifyCollectionChangedAction.Replace:
                        // remove
                        if (e.OldItems != null)
                            for (int i = 0; i < e.OldItems.Count; i++)
                                results.RemoveAt(e.OldStartingIndex);

                        // add
                        goto case NotifyCollectionChangedAction.Add;

                    case NotifyCollectionChangedAction.Reset:
                        results.Clear();
                        if (e.NewItems != null)
                            for (int i = 0; i < e.NewItems.Count; i++)
                                results.Add(createResult((Tsource)e.NewItems[i]));
                        break;

                    default:
                        break;
                }
            };

            foreach (var model in sources)
            {
                results.Add(createResult(model));
            }
            return new ReadOnlyObservableCollection<Tresult>(results);
        }
    }
}
